﻿using huqiang.Core.UIData;
using huqiang.Data;
using huqiang.UIComposite;
using huqiang.UIEvent;
using System;
using System.Collections.Generic;
using UnityEngine;

namespace huqiang.Core.HGUI
{
    public class UIType
    {
        public const string UIElement = "UIElement";
        public const string HCanvas = "HCanvas";
        public const string HGraphics = "HGraphics";
        public const string HImage = "HImage";
        public const string HText = "HText";
        public const string TextBox = "TextBox";
        public const string HLine = "HLine";
    }
    [Serializable]
    public  class UIElement
    {
#if UNITY_EDITOR
        [NonSerialized]
        [HideInInspector]
        public Transform Context;
        [SerializeField]
        [HideInInspector]
        bool _expand;
        public bool expand { get => _expand;
            set {
                _expand = value;
            } }
        public virtual void InitialData()
        { 
        }
        public virtual void SaveData()
        {
        }
#endif
        protected static List<UIElement> Buffer = new List<UIElement>();
        public static void DisposeAll()
        {
            int c = Buffer.Count - 1;
            var arr = Buffer.ToArray();
            for (int i = c; i >= 0; i--)
            {
                var ui = arr[i];
                if(ui==null)
                {
                    UnityEngine.Debug.LogError("UI is null");
                }else
                arr[i].Dispose(); 
            }
            Buffer.Clear();
        }
        public static UIElement FindInstance(int insID)
        {
            for (int i = 0; i < Buffer.Count; i++)
                if (Buffer[i].id == insID)
                    return Buffer[i];
            return null;
        }
        static int ID = 10000;
        /// <summary>
        /// 请勿更改,用于回收时的标记
        /// </summary>
        public virtual string TypeName { get => UIType.UIElement; }
        [SerializeField]
        [HideInInspector]
        internal int id;
        public int GetInstanceID()
        {
            return id;
        }
        public UIElement()
        {
            id = ID;
            ID++;
            Buffer.Add(this);
        }
        public virtual void Dispose()
        {
            Buffer.Remove(this);
            parent = null;
            for (int i = 0; i < child.Count; i++)
                child[i].Dispose();
            child.Clear();
        }
        /// <summary>
        /// 清除资源
        /// </summary>
        public virtual void Clear()
        {
        }
        public bool activeSelf = true;
        public string name;
        public Vector3 localPosition;
        public Vector3 localScale = Vector3.one;
        public Quaternion localRotation = Quaternion.identity;
        public Vector3 Position {
            get 
            {
               return UIAdaptive.GetGlobaInfo(this, false).Position;
            } 
            set
            {
                if(this.parent==null)
                {
                    localPosition = value;
                    return;
                }
                var coord = UIAdaptive.GetGlobaInfo(this.parent, false);
                var v = value - coord.Position;
                v.x /= coord.Scale.x;
                v.y /= coord.Scale.y;
                localPosition = v;
            }
        }
        public Vector3 Scale {
            get 
            {
                return UIAdaptive.GetGlobaInfo(this, false).Scale;
            } 
            set 
            {
                if (this.parent == null)
                {
                    localScale = value;
                    return;
                }
                var coord = UIAdaptive.GetGlobaInfo(this.parent, false);
                value.x /= coord.Scale.x;
                value.y /= coord.Scale.y;
                localScale = value;
            } 
        }
        public Quaternion Rotation { 
            get 
            { 
                return UIAdaptive.GetGlobaInfo(this, false).Rotation; 
            }
            set
            {
                if (this.parent == null)
                {
                    localRotation = value;
                    return;
                }
                var coord = UIAdaptive.GetGlobaInfo(this.parent, false);
                localRotation = value * Quaternion.Inverse(coord.Rotation);
            } 
        }
        public Coordinates coordinate {
            get {
                return UIAdaptive.GetGlobaInfo(this,false);
            }
            set 
            {
                if (this.parent == null)
                {
                    localPosition = value.Position;
                    localScale = value.Scale;
                    localRotation = value.Rotation;
                    return;
                }
                var coord = UIAdaptive.GetGlobaInfo(this.parent, false);
                var v = value.Position - coord.Position;
                v.x /= coord.Scale.x;
                v.y /= coord.Scale.y;
                localPosition = v;
                value.Scale.x /= coord.Scale.x;
                value.Scale.y /= coord.Scale.y;
                localScale = value.Scale;
                localRotation = value.Rotation * Quaternion.Inverse(coord.Rotation);
            } 
        }
        internal UIElement _parent;
        [NonSerialized]
        [HideInInspector]
        public List<UIElement> child = new List<UIElement>();
        public int childCount { get => child.Count; }
        public UIElement GetChild(int index)
        {
            return child[index];
        }
        public UIElement parent
        {
            get { return _parent; }
            set
            {
                if (_parent != null)
                    _parent.child.Remove(this);
                _parent = value;
                if (_parent != null)
                    _parent.child.Add(this);
            }
        }
        public UIElement root { get {
                if (_parent != null)
                {
                    var p = _parent;
                    for(int i=0;i<1024;i++)
                    {
                        if (p._parent == null)
                            break;
                        p = p._parent;
                    }
                    return p;
                }
                return this;
            }
        }
        public void SetParent(UIElement ele)
        {
            if (_parent != null)
                _parent.child.Remove(this);
            _parent = ele;
            if (_parent != null)
                _parent.child.Add(this);
        }
        public void SetAsFirstSibling()
        {
            if(_parent!=null)
            {
                _parent.child.Remove(this);
                _parent.child.Insert(0,this);
            }
        }
        public void SetAsLastSibling()
        {
            if (_parent != null)
            {
                _parent.child.Remove(this);
                _parent.child.Add(this);
            }
        }
        public int GetSiblingIndex()
        {
            if (parent == null)
                return 0;
            return parent.child.IndexOf(this);
        }
        public void SetSiblingIndex(int index)
        {
            if (parent == null)
                return;
            var c = parent.child;
            c.Remove(this);
            if (index >= c.Count)
                c.Add(this);
            else c.Insert(index, this);
        }
        public UIElement Find(string name)
        {
            for (int i = 0; i < child.Count; i++)
                if (child[i].name == name)
                    return child[i];
            return null;
        }
        public T GetComponentInChildren<T>()where T:UIElement
        {
            for (int i = 0; i < child.Count; i++)
            {
                T t = child[i] as T;
                if (t != null)
                    return t;
            }
            return null;
        }

        /// <summary>
        /// 最后更新的帧数,防止同一帧内重复更新
        /// </summary>
        internal int LateFrame;
        [SerializeField]
        internal Vector2 m_sizeDelta = new Vector2(100, 100);
        public virtual Vector2 SizeDelta { get => m_sizeDelta; set => m_sizeDelta = value; }
        /// <summary>
        /// 轴心
        /// </summary>
        public Vector2 Pivot = new Vector2(0.5f, 0.5f);
        //public Vector2 DesignSize;
        /// <summary>
        /// 缩放类型
        /// </summary>
        public ScaleType scaleType;
        /// <summary>
        /// 停靠类型
        /// </summary>
        public AnchorType anchorType;
        /// <summary>
        /// 停靠的点类型
        /// </summary>
        public AnchorPointType anchorPointType;
        /// <summary>
        /// 停靠的偏移位置
        /// </summary>
        public Vector2 anchorOffset;
        /// <summary>
        /// 相对与父物体的剔除尺寸的类型
        /// </summary>
        public MarginType marginType;
        /// <summary>
        /// 父物体类型
        /// </summary>
        public ParentType parentType;
        /// <summary>
        /// 相对与父物体的剔除尺寸
        /// </summary>
        public Margin margin;
        /// <summary>
        /// 用户事件类型
        /// </summary>
        public HEventType eventType;
        /// <summary>
        /// 复合型UI类型
        /// </summary>
        public CompositeType compositeType;
        /// <summary>
        /// 主线脚本更新
        /// </summary>
        public virtual void MainUpdate()
        {
            if (userEvent != null)
            {
                if (userEvent.Frame != LateFrame)
                {
                    userEvent.Frame = LateFrame;
                    userEvent.Update();
                }
                else
                {
                    UnityEngine.Debug.Log("事件重复调用");
                }
            }
            if (composite != null)
            {
                if (composite.Frame != LateFrame)
                {
                    composite.Frame = LateFrame;
                    composite.Update(UserAction.TimeSlice);
                }
                else
                {
                    UnityEngine.Debug.Log("组合件重复调用");
                }
            }
        }
        /// <summary>
        /// 分线程脚本更新
        /// </summary>
        public virtual void SubUpdate()
        {

        }
        /// <summary>
        /// 重新计算尺寸
        /// </summary>
        public virtual void ReSized()
        {
            if (SizeChanged != null)
                SizeChanged(this);
        }
        /// <summary>
        /// 是否开启遮罩
        /// </summary>
        public bool Mask;
        [NonSerialized]
        [HideInInspector]
        /// <summary>
        /// 用户事件
        /// </summary>
        public UserEvent userEvent;
        [NonSerialized]
        [HideInInspector]
        /// <summary>
        /// 复合ui组件实体
        /// </summary>
        public Composite composite;
        [NonSerialized]
        [HideInInspector]
        /// <summary>
        /// 数据模型
        /// </summary>
        public FakeStruct mod;
        [NonSerialized]
        [HideInInspector]
        /// <summary>
        /// 联系上下文
        /// </summary>
        public object DataContext;
        /// <summary>
        /// 在流水线中的位置
        /// </summary>
        internal int PipelineIndex;
        [SerializeField]
        internal Color32 m_color = Color.white;
        /// <summary>
        /// 主颜色
        /// </summary>
        public virtual Color32 MainColor { get => m_color; set => m_color = value; }
        /// <summary>
        /// 注册用户事件
        /// </summary>
        /// <typeparam name="T">事件类型</typeparam>
        /// <param name="fake">数据模型,可空</param>
        /// <returns></returns>
        public T RegEvent<T>(FakeStruct fake) where T : UserEvent, new()
        {
            var t = userEvent as T;
            if (t != null)
                return t;
            t = new T();
            t.Context = this;
            t.Initial(fake);
            userEvent = t;
            t.g_color = MainColor;
            return t;
        }
        /// <summary>
        /// 注册事件
        /// </summary>
        /// <typeparam name="T">类型</typeparam>
        /// <param name="collider">事件检测碰撞器,可空</param>
        /// <returns></returns>
        public T RegEvent<T>(EventCollider collider = null) where T : UserEvent, new()
        {
            var t = userEvent as T;
            if (t != null)
                return t;
            t = new T();
            t.Context = this;
            if (collider == null)
                t.collider = new UIBoxCollider();
            else t.collider = collider;
            userEvent = t;
            t.g_color = MainColor;
            return t;
        }
        [NonSerialized]
        /// <summary>
        /// 当UI尺寸被改变时,执行此委托
        /// </summary>
        public Action<UIElement> SizeChanged;
        /// <summary>
        /// 初始化数据
        /// </summary>
        /// <param name="ex">数据模型</param>
        public void Initial(FakeStruct ex, UIInitializer initializer)
        {
            switch (eventType)
            {
                case HEventType.None: break;
                case HEventType.UserEvent: RegEvent<UserEvent>(ex); break;
                case HEventType.TextInput: RegEvent<InputBoxEvent>(ex); break;
                case HEventType.GestureEvent: RegEvent<GestureEvent>(ex); break;
            }
            CreateUIComposite(this, ex, initializer);
        }
        /// <summary>
        /// 创建复合型UI实体
        /// </summary>
        /// <param name="script">ui元素实体</param>
        /// <param name="ex">数据模型</param>
        public static void CreateUIComposite(UIElement script, FakeStruct ex, UIInitializer initializer)
        {
            switch (script.compositeType)
            {
                case CompositeType.None:
                    break;
                case CompositeType.ScrollY:
                    new ScrollY().Initial(ex, script, initializer);
                    break;
                case CompositeType.ScrollX:
                    new ScrollX().Initial(ex, script, initializer);
                    break;
                case CompositeType.Slider:
                    new UISlider().Initial(ex, script, initializer);
                    break;
                case CompositeType.GridScroll:
                    new GridScroll().Initial(ex, script, initializer);
                    break;
                case CompositeType.Paint:
                    new Paint().Initial(ex, script, initializer);
                    break;
                case CompositeType.Rocker:
                    new UIRocker().Initial(ex, script, initializer);
                    break;
                case CompositeType.UIContainer:
                    new UIContainer().Initial(ex, script, initializer);
                    break;
                case CompositeType.TreeView:
                    new TreeView().Initial(ex, script, initializer);
                    break;
                case CompositeType.UIDate:
                    new UIDate().Initial(ex, script, initializer);
                    break;
                case CompositeType.UIPalette:
                    new UIPalette().Initial(ex, script, initializer);
                    break;
                case CompositeType.ScrollYExtand:
                    new ScrollYExtand().Initial(ex, script, initializer);
                    break;
                case CompositeType.DropDown:
                    new DropdownEx().Initial(ex, script, initializer);
                    break;
                case CompositeType.StackPanel:
                    new StackPanel().Initial(ex, script, initializer);
                    break;
                case CompositeType.DragContent:
                    new DragContent().Initial(ex, script, initializer);
                    break;
                case CompositeType.TabControl:
                    new TabControl().Initial(ex, script, initializer);
                    break;
                case CompositeType.DockPanel:
                    new SplitView().Initial(ex, script, initializer);
                    break;
                case CompositeType.DesignedDockPanel:
                    new DesignedSplitView().Initial(ex, script, initializer);
                    break;
                case CompositeType.DataGrid:
                    new DataGrid().Initial(ex, script, initializer);
                    break;
                case CompositeType.InputBox:
                    new InputBox().Initial(ex, script, initializer);
                    break;
                case CompositeType.PopMenu:
                    new PopMenu().Initial(ex, script, initializer);
                    break;
                case CompositeType.AppendText:
                    new AppendText().Initial(ex, script, initializer);
                    break;
                case CompositeType.GridLayout:
                    new UIComposite.GridLayout().Initial(ex, script, initializer);
                    break;
            }
        }
    }
}
